class dd_trend:
    def __init__(self,factor=0.005):
        self.factor=factor#默认千1
        self.preb=None
        self.fx=0
    def oncalc(self,b,timekey=None):
        if self.preb:
            if self.fx > 0:  # 上涨中找顶
                if b["low"]<self.preb["low"]*(1-self.factor):
                    p=max(self.preb["open"],self.preb["close"])
                    if b["close"]<=p*(1-self.factor):
                        self.fx=-2
                if self.fx==2:
                    self.fx=1
            elif self.fx < 0:  # 下跌中找堤
                if b["high"]>self.preb["high"]*(1+self.factor):
                    p=min(self.preb["open"],self.preb["close"])
                    if b["close"]>=p*(1+self.factor):
                        self.fx=2
                if self.fx==-2:
                    self.fx=-1
            else:
                if b["high"] > self.preb["high"] * (1 + self.factor):
                    self.fx=1
                elif b["low"]<self.preb["low"]*(1-self.factor):
                    self.fx=-1
        self.preb=b
        rst=self.fx
        return rst
class dd_trend_bars:
    def __init__(self,bars=2,isclose=True):
        self.bars=bars#默认千1
        self.prebs=[]
        self.fx=0
        if isclose:
            self.oncalc=self.oncalc_True
        else:
            self.oncalc = self.oncalc_False
    def oncalc_False(self,b,timekey=None):
        if len(self.prebs) == self.bars:
            if self.fx > 0:
                r = True
                for n in range(self.bars):
                    r = r and b["close"] < self.prebs[n]["close"] and b["low"] < self.prebs[n]["low"]
                    if not r:
                        break
                if self.fx == 2:
                    self.fx = 1
                if r:
                    self.fx = -2
            elif self.fx < 0:
                r = True
                for n in range(self.bars):
                    r = r and b["close"] > self.prebs[n]["close"] and b["high"] > self.prebs[n]["high"]
                    if not r:
                        break
                if self.fx == -2:
                    self.fx = -1
                if r:
                    self.fx = 2
            else:
                if b["close"] > self.prebs[-1]["close"]:
                    self.fx = 1
                elif b["close"] < self.prebs[-1]["close"]:
                    self.fx = -1
        self.prebs.append(b)
        rst = self.fx
        return rst
    def oncalc_True(self,b,timekey=None):
        if len(self.prebs)==self.bars:
            if self.fx>0:
                r=True
                for n in range(self.bars):
                    r=r and b["close"]<self.prebs[n]["low"]
                    if not r:
                        break
                if self.fx==2:
                    self.fx=1
                if r:
                    self.fx=-2
            elif self.fx<0:
                r = True
                for n in range(self.bars):
                    r = r and b["close"] > self.prebs[n]["high"]
                    if not r:
                        break
                if self.fx == -2:
                    self.fx = -1
                if r:
                    self.fx = 2
            else:
                if b["close"]>self.prebs[-1]["close"]:
                    self.fx=1
                elif b["close"]<self.prebs[-1]["close"]:
                    self.fx=-1
            self.prebs.pop(0)
        self.prebs.append(b)
        rst=self.fx
        return rst

    class dd_trend_bars:
        def __init__(self, bars=2, isclose=True):
            self.bars = bars  # 默认千1
            self.prebs = []
            self.fx = 0
            if isclose:
                self.oncalc = self.oncalc_True
            else:
                self.oncalc = self.oncalc_False

        def oncalc_False(self, b, timekey=None):
            if len(self.prebs) == self.bars:
                if self.fx > 0:
                    r = True
                    for n in range(self.bars):
                        r = r and b["close"] < self.prebs[n]["close"] and b["low"] < self.prebs[n]["low"]
                        if not r:
                            break
                    if self.fx == 2:
                        self.fx = 1
                    if r:
                        self.fx = -2
                elif self.fx < 0:
                    r = True
                    for n in range(self.bars):
                        r = r and b["close"] > self.prebs[n]["close"] and b["high"] > self.prebs[n]["high"]
                        if not r:
                            break
                    if self.fx == -2:
                        self.fx = -1
                    if r:
                        self.fx = 2
                else:
                    if b["close"] > self.prebs[-1]["close"]:
                        self.fx = 1
                    elif b["close"] < self.prebs[-1]["close"]:
                        self.fx = -1
                self.prebs.pop(0)
            self.prebs.append(b)
            rst = self.fx
            return rst

        def oncalc_True(self, b, timekey=None):
            if len(self.prebs) == self.bars:
                if self.fx > 0:
                    r = True
                    for n in range(self.bars):
                        r = r and b["close"] < self.prebs[n]["low"]
                        if not r:
                            break
                    if self.fx == 2:
                        self.fx = 1
                    if r:
                        self.fx = -2
                elif self.fx < 0:
                    r = True
                    for n in range(self.bars):
                        r = r and b["close"] > self.prebs[n]["high"]
                        if not r:
                            break
                    if self.fx == -2:
                        self.fx = -1
                    if r:
                        self.fx = 2
                else:
                    if b["close"] > self.prebs[-1]["close"]:
                        self.fx = 1
                    elif b["close"] < self.prebs[-1]["close"]:
                        self.fx = -1
                self.prebs.pop(0)
            self.prebs.append(b)
            rst = self.fx
            return rst

class dd_bars_n:
    def __init__(self,isclose=True,maxn=10,isbreak=True):
        self.prebs=[]
        self.maxn=maxn
        self.isbreak=isbreak
        if isclose:
            self.oncalc=self.oncalc_True
        else:
            self.oncalc = self.oncalc_False
    def oncalc_False(self,b,timekey=None):
        up = 0
        down = 0
        if len(self.prebs)==self.maxn:
            r_up = True
            r_down=True
            isbreak_up=False
            isbreak_down=False
            for i in reversed(self.prebs):
                if self.isbreak:
                    r_up = r_up and b["close"] > i["close"] and b["high"] < i["high"]
                    r_down = r_down and b["close"] < i["close"] and b["low"] < i["low"]
                    if not r_up:
                        isbreak_up=True
                    if not r_down:
                        isbreak_down=True
                    if not isbreak_up:
                        up=up+1
                    if not isbreak_down:
                        down=down+1
                    if isbreak_up and isbreak_up:
                        break
                else:
                    r_up = b["close"] > i["close"] and b["high"] < i["high"]
                    r_down = b["close"] < i["close"] and b["low"] < i["low"]
                    if r_up:
                        up = up + 1
                    if r_down:
                        down=down+1
            self.prebs.pop(0)
        self.prebs.append(b)
        return up,-down
    def oncalc_True(self,b,timekey=None):
        up = 0
        down = 0
        if len(self.prebs) == self.maxn:
            r_up = True
            r_down = True
            isbreak_up = False
            isbreak_down = False
            for i in reversed(self.prebs):
                if self.isbreak:
                    r_up = r_up and b["close"] > i["high"]
                    r_down = r_down and b["close"] < i["low"]
                    if not r_up:
                        isbreak_up = True
                    if not r_down:
                        isbreak_down = True
                    if not isbreak_up:
                        up = up + 1
                    if not isbreak_down:
                        down = down + 1
                    if isbreak_up and isbreak_up:
                        break
                else:
                    r_up = b["close"] > i["high"]
                    r_down = b["close"] < i["low"]
                    if r_up:
                        up = up + 1
                    if r_down:
                        down = down + 1
            self.prebs.pop(0)
        self.prebs.append(b)
        return up, -down
if __name__=="__main__":
    cc=[
        {'calc_cmd': 'class', "class": "dd_trend", "out": ["dd_trend0"],
         "init_args": {"factor": 0}},
        {'calc_cmd': 'class', "class": "dd_trend", "out": ["dd_trend1"],
         "init_args": {"factor": 0.005}},
        {'calc_cmd': 'class', "class": "dd_trend", "out": ["dd_trend2"],
         "init_args": {"factor": 0.01}},
        {'calc_cmd': 'class', "class": "dd_trend_bars", "out": ["dd_trends1True"],
         "init_args": {"bars":1,"isclose":True}},
        {'calc_cmd': 'class', "class": "dd_trend_bars", "out": ["dd_trends2True"],
         "init_args": {"bars": 2, "isclose": True}},
        {'calc_cmd': 'class', "class": "dd_trend_bars", "out": ["dd_trends3True"],
         "init_args": {"bars": 3, "isclose": True}},
        {'calc_cmd': 'class', "class": "dd_trend_bars", "out": ["dd_trends1False"],
         "init_args": {"bars": 1, "isclose": False}},
        {'calc_cmd': 'class', "class": "dd_trend_bars", "out": ["dd_trends2False"],
         "init_args": {"bars": 2, "isclose": False}},
        {'calc_cmd': 'class', "class": "dd_trend_bars", "out": ["dd_trends3False"],
         "init_args": {"bars": 3, "isclose": False}},
        {'calc_cmd': 'class', "class": "dd_bars_n", "out": ["dd_bars_n3True_up","dd_bars_n3True_down"],
         "init_args": {"maxn": 3, "isclose": True}},
        {'calc_cmd': 'class', "class": "dd_bars_n", "out": ["dd_bars_n5True_up","dd_bars_n5True_down"],
         "init_args": {"maxn": 5, "isclose": True}},
        {'calc_cmd': 'class', "class": "dd_bars_n", "out": ["dd_bars_n10True_up","dd_bars_n10True_down"],
         "init_args": {"maxn": 10, "isclose": True}},
        {'calc_cmd': 'class', "class": "dd_bars_n", "out": ["dd_bars_n3False_up","dd_bars_n3False_down"],
         "init_args": {"maxn": 3, "isclose": False}},
        {'calc_cmd': 'class', "class": "dd_bars_n", "out": ["dd_bars_n5False_up","dd_bars_n5False_down"],
         "init_args": {"maxn": 5, "isclose": False}},
        {'calc_cmd': 'class', "class": "dd_bars_n", "out": ["dd_bars_n10False_up","dd_bars_n10False_down"],
         "init_args": {"maxn": 10, "isclose": False}},
        {'calc_cmd': 'class', "class": "dd_bars_n", "out": ["dd0_bars_n3True_up", "dd0_bars_n3True_down"],
         "init_args": {"maxn": 3, "isclose": True,"isbreak":False}},
        {'calc_cmd': 'class', "class": "dd_bars_n", "out": ["dd0_bars_n5True_up", "dd0_bars_n5True_down"],
         "init_args": {"maxn": 5, "isclose": True,"isbreak":False}},
        {'calc_cmd': 'class', "class": "dd_bars_n", "out": ["dd0_bars_n10True_up", "dd0_bars_n10True_down"],
         "init_args": {"maxn": 10, "isclose": True,"isbreak":False}},
        {'calc_cmd': 'class', "class": "dd_bars_n", "out": ["dd0_bars_n3False_up", "dd0_bars_n3False_down"],
         "init_args": {"maxn": 3, "isclose": False,"isbreak":False}},
        {'calc_cmd': 'class', "class": "dd_bars_n", "out": ["dd0_bars_n5False_up", "dd0_bars_n5False_down"],
         "init_args": {"maxn": 5, "isclose": False,"isbreak":False}},
        {'calc_cmd': 'class', "class": "dd_bars_n", "out": ["dd0_bars_n10False_up", "dd0_bars_n10False_down"],
         "init_args": {"maxn": 10, "isclose": False,"isbreak":False}}
    ]
    from research.calcor.calcor_show import calcor_show

    calcor_show(obj="ec888",start="20240103",end="20240731",cc=cc,factors=[],prebatch=10,main_names=[],
                sub_names=[
                    ("line", ["dd0_bars_n3True_up", "dd0_bars_n5True_up", "dd0_bars_n10True_up",
                              "dd0_bars_n3False_up", "dd0_bars_n5False_up", "dd0_bars_n10False_up"]),
                    ("line", ["dd0_bars_n3True_down", "dd0_bars_n5True_down", "dd0_bars_n10True_down",
                              "dd0_bars_n3False_down", "dd0_bars_n5False_down", "dd0_bars_n10False_down"]),
                    ("line", ["dd_bars_n3True_up", "dd_bars_n5True_up", "dd_bars_n10True_up",
                              "dd_bars_n3False_up", "dd_bars_n5False_up", "dd_bars_n10False_up"]),
                    ("line", ["dd_bars_n3True_down", "dd_bars_n5True_down", "dd_bars_n10True_down",
                              "dd_bars_n3False_down", "dd_bars_n5False_down", "dd_bars_n10False_down"]),
                    ("line", ["dd_trends1True", "dd_trends2True", "dd_trends3True",
                              "dd_trends1False", "dd_trends2False", "dd_trends3False"]),
                    ("line",["dd_trend0","dd_trend1","dd_trend2"])])